﻿using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using MongoDB.Bson.Serialization.Attributes;

namespace EasyXaf.MongoDB;

public class EasyXafMongoDBModule : ModuleBase
{
    private static IMemberInfo FindAssociationMemberInfo(IMemberInfo memberInfo)
    {
        var association = memberInfo.FindAttribute<MongoAssociationAttribute>();
        if (association == null)
        {
            return null;
        }

        var associationName = association.AssociationName;
        var targetTypeInfo = memberInfo.IsList
            ? memberInfo.ListElementTypeInfo
            : memberInfo.MemberTypeInfo;

        return string.IsNullOrWhiteSpace(associationName)
            ? targetTypeInfo.Members.FirstOrDefault(m => (m.IsList ? m.ListElementTypeInfo : m.MemberTypeInfo) == memberInfo.Owner)
            : targetTypeInfo.Members
                .Where(m => m.FindAttribute<MongoAssociationAttribute>()?.AssociationName == associationName)
                .FirstOrDefault();
    }

    public override void CustomizeTypesInfo(ITypesInfo typesInfo)
    {
        base.CustomizeTypesInfo(typesInfo);

        foreach (var typeInfo in typesInfo.PersistentTypes)
        {
            if (typeof(MongoEntity).IsAssignableFrom(typeInfo.Type))
            {
                ((TypeInfo)typeInfo).IsPersistent = true;

                foreach (var memberInfo in typeInfo.Members.OfType<XafMemberInfo>())
                {
                    if (memberInfo.IsPublic
                        && !memberInfo.IsReadOnly
                        && !memberInfo.IsCustom
                        && !memberInfo.IsAttributeDefined<BsonIgnoreAttribute>(true))
                    {
                        memberInfo.IsPersistent = true;
                    }

                    var associationMemberInfo = FindAssociationMemberInfo(memberInfo);
                    if (associationMemberInfo != null)
                    {
                        memberInfo.IsAssociation = true;
                        memberInfo.AssociatedMemberInfo = (XafMemberInfo)associationMemberInfo;
                        memberInfo.AssociatedMemberOwner = associationMemberInfo.Owner.Type;
                        memberInfo.AssociatedMemberName = associationMemberInfo.Name;
                    }
                }
            }
        }
    }
}
